package com.fengmi.service;

import com.api.goods.GoodsApi;
import com.fengmi.dto.SearchDTO;
import com.fengmi.entity.ESGoods;
import com.fengmi.goods.entity.MallGoods;
import com.fengmi.vo.PageResultVo;
import com.fengmi.vo.ResultVO;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class SearchService implements ISearchService{

//
//
//    @mysql2es
//    public  void  add(){
//        //insert into mysql
//
//
//
//    }
//    @mysql2es
//    public  void  update(){
//        //insert into mysql
//
//
//
//    }
//
//
//    @mysql2es
//    public  void  delete(){
//        //insert into mysql
//
//
//
//    }





    @Autowired
    private GoodsApi goodsApi;


    @Autowired
    private ElasticsearchRestTemplate restTemplate;

    @Override
    public ResultVO init() {


        //删除索引库
        restTemplate.deleteIndex(ESGoods.class);


        //创建索引库
        restTemplate.createIndex(ESGoods.class);

        restTemplate.putMapping(ESGoods.class);


        //远程调用goods服务获取商品信息
        List<MallGoods> goodsList = goodsApi.findGoodsHasAuditedForEs();

        //List<esgoods>
        List<ESGoods> esGoodsList = goodsList.stream().map(spu -> {
            ESGoods esGoods = new ESGoods();
            esGoods.setSpuId(spu.getSpuId());
            esGoods.setBrandId(spu.getBrand().getId());
            esGoods.setBrandName(spu.getBrand().getName());


            esGoods.setCat1id(spu.getCat1().getId());
            esGoods.setCat1name(spu.getCat1().getName());
            esGoods.setCat2id(spu.getCat2().getId());
            esGoods.setCat2name(spu.getCat2().getName());
            esGoods.setCat3id(spu.getCat3().getId());
            esGoods.setCat3name(spu.getCat3().getName());

            esGoods.setCreateTime(new Date());
            esGoods.setGoodsName(spu.getGoodsName());
            esGoods.setSale(spu.getSale()!=null?Long.parseLong(spu.getSale() + ""):0);
            esGoods.setPrice(spu.getPrice().doubleValue());

            esGoods.setImageUrl(spu.getAlbumPics());

            return esGoods;
        }).collect(Collectors.toList());


        //批量插入
        restTemplate.save(esGoodsList);

        return new ResultVO(true,"初始化成功");
    }

    @Override
    public PageResultVo<ESGoods> search(SearchDTO searchDTO) {


        if (searchDTO == null) {
            return  new PageResultVo<>(false,"非法参数");
        }

        //1：关键字查询（bool）
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        if(!StringUtils.isEmpty(searchDTO.getKeyword())){
            //keyword match goodsname
            MatchQueryBuilder goodsName = QueryBuilders.matchQuery("goodsName", searchDTO.getKeyword());
            //keyword match brand
            MatchQueryBuilder brandName = QueryBuilders.matchQuery("brandName", searchDTO.getKeyword());
            //keyword match cat3name
            MatchQueryBuilder cat3name = QueryBuilders.matchQuery("cat3name", searchDTO.getKeyword());
            boolQueryBuilder.should(goodsName).should(brandName).should(cat3name);

        }


        //9：过滤掉已经删除的数据
        TermQueryBuilder is_delete = QueryBuilders.termQuery("is_delete", "0");
        boolQueryBuilder.filter(is_delete);


        //2:分页
        PageRequest pageRequest = PageRequest.of((searchDTO.getPage()-1)<0?0:(searchDTO.getPage()-1), searchDTO.getSize());

        //3:高亮
        HighlightBuilder goodsNameHighlightBuilder = getHighlightBuilder("goodsName");


        //4:品牌聚合
        TermsAggregationBuilder brandName = AggregationBuilders.terms("brand_type").field("brandName").size(100);
        //5:三级分类聚合
        TermsAggregationBuilder cat3name = AggregationBuilders.terms("cat3name_type").field("cat3name").size(100);


        //6:品牌过滤
        if(!StringUtils.isEmpty(searchDTO.getBrandNameFilter())){
            TermQueryBuilder brandNameFilter = QueryBuilders.termQuery("brandName", searchDTO.getBrandNameFilter());
            boolQueryBuilder.filter(brandNameFilter);
        }

        //7:三级分类过滤
        if(!StringUtils.isEmpty(searchDTO.getCat3NmaeFilter())){
            TermQueryBuilder cat3nameFiler = QueryBuilders.termQuery("cat3name", searchDTO.getCat3NmaeFilter());
            boolQueryBuilder.filter(cat3nameFiler);
        }
        FieldSortBuilder priceSort = null;
        //8:按价格排序
        if(!StringUtils.isEmpty(searchDTO.getPriceSort())&& searchDTO.getPriceSort().equals("asc")){
            //价格升序
            priceSort = SortBuilders.fieldSort("price").order(SortOrder.ASC);
        }

        if(!StringUtils.isEmpty(searchDTO.getPriceSort())&& searchDTO.getPriceSort().equals("desc")){
            //价格升序
             priceSort = SortBuilders.fieldSort("price").order(SortOrder.DESC);
        }


        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
                //指定查询方式
                .withQuery(boolQueryBuilder)
                //设置分页
                .withPageable(pageRequest)
                //设置高亮
                .withHighlightBuilder(goodsNameHighlightBuilder)
                //设置聚合(品牌)
                .addAggregation(brandName)
                //设置聚合（三级分类）
                .addAggregation(cat3name);



        if(priceSort != null){
            nativeSearchQueryBuilder.withSort(priceSort);
        }


        SearchHits<ESGoods> search = restTemplate.search(nativeSearchQueryBuilder.build(), ESGoods.class);

        List<SearchHit<ESGoods>> searchHits = search.getSearchHits();
        List<ESGoods> esGoodsList = searchHits.stream().map(hit -> {

            ESGoods esGoods = hit.getContent();
            Map<String, List<String>> highlightFields = hit.getHighlightFields();

            //取高亮
            highlightFields.forEach((k,v)->{
                if("goodsName".equals(k)){
                    esGoods.setGoodsName(v.get(0));
                }
            });


            return  esGoods;


        }).collect(Collectors.toList());

        PageResultVo<ESGoods> pageResultVo = new PageResultVo<>(true,"success");

        //取分页信息
        pageResultVo.setData(esGoodsList);
        pageResultVo.setTotal(search.getTotalHits());

        //取品牌聚合信息
        Aggregations aggregations = search.getAggregations();
        Terms brand_type = aggregations.get("brand_type");

        List<String> brandList = brand_type.getBuckets().stream().map(b ->(String) b.getKey()).collect(Collectors.toList());
        pageResultVo.setBrandList(brandList);


        //取三级分类的聚合列表
        Terms cat3name_type = aggregations.get("cat3name_type");
        List<String> cat3NameList = cat3name_type.getBuckets().stream().map(b -> (String) b.getKey()).collect(Collectors.toList());
        pageResultVo.setCat3NameList(cat3NameList);
        return pageResultVo;
    }



    // 设置高亮字段
    private HighlightBuilder getHighlightBuilder(String... fields) {
        // 高亮条件
        HighlightBuilder highlightBuilder = new HighlightBuilder(); //生成高亮查询器
        for (String field : fields) {
            highlightBuilder.field(field);//高亮查询字段
        }
        highlightBuilder.requireFieldMatch(false);     //如果要多个字段高亮,这项要为false
        highlightBuilder.preTags("<span style=\"color:red\">");   //高亮设置
        highlightBuilder.postTags("</span>");
        //下面这两项,如果你要高亮如文字内容等有很多字的字段,必须配置,不然会导致高亮不全,文章内容缺失等
        highlightBuilder.fragmentSize(800000); //最大高亮分片数
        highlightBuilder.numOfFragments(0); //从第一个分片获取高亮片段

        return highlightBuilder;
    }
}
